using System.Collections;
using System.Collections.Generic;
using Baula.Testing.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Baula.TextGen.ActiveTemplating.Tests
{
    [TestClass]
    public class ReadAheadEnumeratorTests
    {
        private class Item
        {
            private readonly char _character;

            public Item(char character)
            {
                _character = character;
            }

            public char Character
            {
                get { return _character; }
            }
        }

        private class Items : IEnumerable<Item>
        {
            private readonly IList<Item> _items = new List<Item>();

            public Items(IEnumerable<char> theString)
            {
                foreach (var character in theString)
                {
                    _items.Add(new Item(character));
                }
            }

            public IEnumerator<Item> GetEnumerator()
            {
                return _items.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }

        [TestMethod]
        public void NextItem_OnNewEnumerator_ThrowsException()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("Hello"));
            var exception = ExceptionAssert.Expect(
                () => enumerator.NextItem);

            Assert.AreEqual("Enumeration not started. Call MoveNext() upfront.", exception.Message);
        }

        [TestMethod]
        public void Current_AfterFirstMoveNext_ReturnsFirstItem()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            var actual = enumerator.Current;
            Assert.IsNotNull(actual);
            Assert.AreEqual('a', actual.Character);
        }

        [TestMethod]
        public void NextItem_AfterFirstMoveNext_ReturnsSecondItem()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            var actual = enumerator.NextItem;
            Assert.IsNotNull(actual);
            Assert.AreEqual('b', actual.Character);
        }

        [TestMethod]
        public void Current_AfterSecondMoveNext_ReturnsSecondItem()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            enumerator.MoveNext();
            var actual = enumerator.Current;
            Assert.IsNotNull(actual);
            Assert.AreEqual('b', actual.Character);
        }

        [TestMethod]
        public void NextItem_AfterSecondMoveNext_ReturnsSecondItem()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            enumerator.MoveNext();
            var actual = enumerator.NextItem;
            Assert.IsNotNull(actual);
            Assert.AreEqual('c', actual.Character);
        }

        [TestMethod]
        public void Current_ToLastItem_ReturnsLastItemt()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            enumerator.MoveNext();
            enumerator.MoveNext();
            var actual = enumerator.Current;
            Assert.IsNotNull(actual);
            Assert.AreEqual('c', actual.Character);
        }

        [TestMethod]
        public void NextItem_ToLastItem_ReturnsDefault()
        {
            var enumerator = new ReadAheadEnumerator<Item>(new Items("abc"));
            enumerator.MoveNext();
            enumerator.MoveNext();
            enumerator.MoveNext();
            var actual = enumerator.NextItem;
            Assert.IsNull(actual);
        }
    }
}